using System;
using System.Collections.Generic;
using System.IO;
using Fungus;
using UnityEngine;
using UnityEngine.SceneManagement;
using System.Globalization;

public class CheatMenu : MonoBehaviour
{
	//Using an integer to represent which tab is shown
	//tabState
	//0 = none expanded
	//1 = state expanded
	//2 = commands expanded
	//3 = advanced expanded
	
	public CheatMenu()	
	{
		//Do i really need to idiot proof this...
		string expectedVersionDefault = "v0.29 Final|v0.29 VeryFinal";
		int minButtonHeightDefault = 15;
		int proposedItemCountDefault = 40;
		Color buttonNormalBackColorDefault = new Color(1f, 1f, 1f, 1f);
		Color buttonSelectedBackColorDefault = new Color(1f, 0f, 0f, 1f);
		
		bool shouldWriteConfig = false;
		string settingsPath = Path.Combine(Application.dataPath, "CheatMenu.json");
		Dictionary<string, string> settingsDict;
		if (!File.Exists(settingsPath))
		{
			settingsDict = new Dictionary<string, string>();
			settingsDict["ExpectedVersion"] = expectedVersionDefault;
			settingsDict["MinButtonHeight"] = minButtonHeightDefault.ToString();
			settingsDict["ProposedItemCount"] = proposedItemCountDefault.ToString();
			settingsDict["ButtonNormalBackColor"] = "#" + ColorUtility.ToHtmlStringRGB(buttonNormalBackColorDefault);
			settingsDict["ButtonSelectedBackColor"] = "#" + ColorUtility.ToHtmlStringRGB(buttonSelectedBackColorDefault);
			shouldWriteConfig = true;
		}
		else
		{
			settingsDict = JSONObject.Create(File.ReadAllText(settingsPath)).ToDictionary();
			if(!(settingsDict.ContainsKey("ExpectedVersion") && !string.IsNullOrEmpty(settingsDict["ExpectedVersion"])))
			{
				settingsDict["ExpectedVersion"] = expectedVersionDefault;
				shouldWriteConfig = true;
			}
		
			if(!(settingsDict.ContainsKey("MinButtonHeight") && int.TryParse(settingsDict["MinButtonHeight"], out int ignoreMinButtonHeight)))
			{
				settingsDict["MinButtonHeight"] = minButtonHeightDefault.ToString();
				shouldWriteConfig = true;
			}
		
			if(!(settingsDict.ContainsKey("ProposedItemCount") && int.TryParse(settingsDict["ProposedItemCount"], out int ignoreProposedItemCount)))
			{
				settingsDict["ProposedItemCount"] = proposedItemCountDefault.ToString();
				shouldWriteConfig = true;
			}
			
			if(!(settingsDict.ContainsKey("ButtonNormalBackColor") && ColorUtility.TryParseHtmlString(settingsDict["ButtonNormalBackColor"], out Color ignoreButtonNormalBackColor)))
			{
				settingsDict["ButtonNormalBackColor"] = "#" + ColorUtility.ToHtmlStringRGB(buttonNormalBackColorDefault);
				shouldWriteConfig = true;
			}
			
			if(!(settingsDict.ContainsKey("ButtonSelectedBackColor") && ColorUtility.TryParseHtmlString(settingsDict["ButtonSelectedBackColor"], out Color ignoreButtonSelectedBackColor)))
			{
				settingsDict["ButtonSelectedBackColor"] = "#" + ColorUtility.ToHtmlStringRGB(buttonSelectedBackColorDefault);
				shouldWriteConfig = true;
			}
		}
		
		this.ExpectedVersion = settingsDict["ExpectedVersion"];
		this.minButtonHeight = (float)int.Parse(settingsDict["MinButtonHeight"]);
		this.proposedItemCount = int.Parse(settingsDict["ProposedItemCount"]);
		if(ColorUtility.TryParseHtmlString(settingsDict["ButtonNormalBackColor"], out Color outButtonNormalBackColor))
			this.buttonNormalBackColor = outButtonNormalBackColor;
		if(ColorUtility.TryParseHtmlString(settingsDict["ButtonSelectedBackColor"], out Color outButtonSelectedBackColor))
			this.buttonSelectedBackColor = outButtonSelectedBackColor;

		if(shouldWriteConfig)
			File.WriteAllText(settingsPath, JSONObject.Create(settingsDict).Print(true));
	}
	
	public bool MatchVersion()
	{
		if(!this.versionCheck)
		{
			this.versionCheck = true;
			string[] expectedSplit = this.ExpectedVersion.Split(new char[] { '|' }, StringSplitOptions.RemoveEmptyEntries);
			for (int i = 0; i < expectedSplit.Length; i++)
			{
				if(this.DetectedVersion.Equals(expectedSplit[i], StringComparison.InvariantCultureIgnoreCase))
				{
					this.versionMatched = true;
					break;
				}
			}
		}

		return this.versionMatched;
	}
	
	public void Start()
	{
		//Magic values, these are set by Unity and are just for reference
		this.scrollbarWidth = 16f;
		float titleBarHeight = 10f;
		float paddingSize = 5f;
		
		float proposedButtonHeight = (float)Screen.height / this.proposedItemCount;
		proposedButtonHeight = Math.Max(this.minButtonHeight, proposedButtonHeight);
		this.defaultControlHeight = (int)proposedButtonHeight;
		this.defaultControlWidth = (int)(proposedButtonHeight * 6f);
		this.defaultControlFontSize = (int)(proposedButtonHeight * 0.75f);
		this.menuYOffset = Screen.height * 0.075f;

		this.debugMenu = true;
		this.autoSceneDump = false;
		this.autoSceneDumpPromt = false;
		this.sceneDumpDict = new Dictionary<string, bool>();
		this.blackListScenes = new HashSet<string>(new string[]
		{
			"Start",
			"start_day"
		});

		this.tabState = 1;

		float debugWidth = defaultControlWidth * 1.25f;
		float debugHeight = (this.defaultControlHeight * 7f) + (6f * paddingSize) + titleBarHeight;
		this.debugWindowRect = new Rect(Screen.width - debugWidth, this.menuYOffset, debugWidth, debugHeight);
		float debugConformWidth =  (defaultControlWidth * 4f) + (2f * paddingSize);
		float debugConformHeight = (defaultControlHeight * 7f) + (6f * paddingSize) + titleBarHeight;
		this.dumpConfirmWindowRect = new Rect((Screen.width - debugConformWidth) * 0.5f, this.menuYOffset, debugConformWidth, debugConformHeight);
		
		this.commandsList = new List<KeyValuePair<string, Action>[]>();
		this.commandsList.Add(new KeyValuePair<string, Action>[] {new KeyValuePair<string, Action>("+$100", () => AddInt("money", 100))});
		this.commandsList.Add(new KeyValuePair<string, Action>[] {new KeyValuePair<string, Action>("Full Energy", () => SetInt("energ", GetInt("total_energ")))});
		this.commandsList.Add(new KeyValuePair<string, Action>[] {new KeyValuePair<string, Action>("Full Lube", () => SetInt("lube", 3))});
		this.commandsList.Add(new KeyValuePair<string, Action>[] {new KeyValuePair<string, Action>("Full Condoms", () => SetInt("condoms", 3))});
		this.commandsList.Add(new KeyValuePair<string, Action>[] {new KeyValuePair<string, Action>("Full Suncream", () => SetInt("suncream", 3))});
		this.commandsList.Add(new KeyValuePair<string, Action>[] {new KeyValuePair<string, Action>("Full VitaminX", () => SetInt("drugs", 20))});
		this.commandsList.Add(new KeyValuePair<string, Action>[] {new KeyValuePair<string, Action>("Full PlanB", () => SetInt("mpills", 20))});
		this.commandsList.Add(new KeyValuePair<string, Action>[] {new KeyValuePair<string, Action>("Full Sleeping", () => SetInt("spills", 20))});
		this.commandsList.Add(new KeyValuePair<string, Action>[] {new KeyValuePair<string, Action>("Full Lactation", () => SetInt("lpills", 20))});
		this.commandsList.Add(new KeyValuePair<string, Action>[] {new KeyValuePair<string, Action>("Time-1", () => AddInt("time", -1)),
								new KeyValuePair<string, Action>("Time+1", () => AddInt("time", 1))});

		this.advancedList = new List<KeyValuePair<string, Action>[]>();
		this.advancedList.Add(new KeyValuePair<string, Action>[] {new KeyValuePair<string, Action>("LoadScene", () => 
		{ 
			this.autoSceneDumpPromt = false;
			this.sceneNameInput = "";
			this.loadScenePrompt = !this.loadScenePrompt;
		})});
		//TODO
		//this.advancedList.Add({new KeyValuePair<string, Action>("Exec Block", () => 
		//{ 
		//})});
	}
	
	public void OnGUI()
	{
		Scene activeScene = SceneManager.GetActiveScene();
		if (activeScene.name != this.lastScene)
		{
			this.lastScene = activeScene.name;
			this.initFlowChart = false;
			this.initGuiStyle = false;
			this.flowcharts = null;
			this.foundCharts = 0;
			this.initCounter = 0;
		}
		
		if(!MatchVersion())
		{
			this.InitGuiStyles();	
			GUILayout.Label(string.Format("Version mismatch, Expected: {0}, Detected: {1}", this.ExpectedVersion, this.DetectedVersion), this.labelHeaderStyle);
			return;
		}
		
		if (!this.blackListScenes.Contains(activeScene.name) || this.autoSceneDump)
		{
			this.InitFlowCharts();
			this.InitGuiStyles();
			if (this.initFlowChart)
			{
				if (this.autoSceneDump)
				{
					if(DoAutoSceneDump(out string nextScene, activeScene))
					{
						SceneManager.LoadScene(nextScene);
					}
					else
					{
						this.autoSceneDump = false;
						this.sceneDumpDict.Clear();
						SceneManager.LoadScene("Start");
					}
				}
				this.DisplayCheatMenu();
			}
			if (this.debugMenu)
			{
				this.DrawDebugMenu();
			}
		}
	}

	public void InitFlowCharts()
	{
		if (!this.initFlowChart && this.initCounter < 10)
		{
			this.initCounter++;
			this.flowcharts = UnityEngine.Object.FindObjectsOfType<Flowchart>();
			if (this.flowcharts != null && this.flowcharts.Length != 0)
			{
				this.initFlowChart = true;
				this.foundCharts = this.flowcharts.Length;
			}
		}
	}
	
	public void InitGuiStyles()
	{
		if (!this.initGuiStyle)
		{
			this.initGuiStyle = true;

			this.scrollStateViewVector = Vector2.zero;
			this.scrollCommandsViewVector = Vector2.zero;
			this.scrollAdvancedViewVector = Vector2.zero;
			
			this.defaultButtonStyle = new GUIStyle("button");
			this.defaultButtonStyle.fontSize = this.defaultControlFontSize;
			this.defaultButtonStyle.margin = new RectOffset(0, 0, 0, 0);
			this.defaultButtonStyle.padding = new RectOffset(0, 0, 0, 0);
			
			this.intButtonStyle = new GUIStyle("button");
			this.intButtonStyle.fixedHeight = this.defaultControlHeight;
			this.intButtonStyle.fixedWidth = this.defaultControlHeight;
			this.intButtonStyle.margin = new RectOffset(0, 0, 0, 0);
			this.intButtonStyle.padding = new RectOffset(0, 0, 0, 0);
			this.intButtonStyle.fontSize = this.defaultControlFontSize;
			
			this.boolButtonStyle = new GUIStyle("button");
			this.boolButtonStyle.fixedHeight = this.defaultControlHeight;
			this.boolButtonStyle.fixedWidth = this.defaultControlHeight * 2;
			this.boolButtonStyle.margin = new RectOffset(0, 0, 0, 0);
			this.boolButtonStyle.padding = new RectOffset(0, 0, 0, 0);
			this.boolButtonStyle.fontSize = this.defaultControlFontSize;
			
			this.buttonLayoutOptions = new GUILayoutOption[] {GUILayout.Width(this.defaultControlWidth - this.scrollbarWidth), GUILayout.Height(this.defaultControlHeight)};

			this.buttonHalfLayoutOptions = new GUILayoutOption[] {GUILayout.Width((this.defaultControlWidth - this.scrollbarWidth) * 0.5f), GUILayout.Height(this.defaultControlHeight)};

			this.labelStyle = new GUIStyle
			{
				fixedHeight = this.defaultControlHeight,
				margin = new RectOffset(0, 0, 0, 0),
				padding = new RectOffset(0, 0, 0, 0),
				normal = new GUIStyleState
				{
					textColor = Color.white
				}
			};
			this.labelStyle.fontSize = this.defaultControlFontSize;
			
			this.labelHeaderStyle = new GUIStyle("label");
			this.labelHeaderStyle.fixedHeight = this.defaultControlHeight;
			this.labelHeaderStyle.margin = new RectOffset(0, 0, 0, 0);
			this.labelHeaderStyle.padding = new RectOffset(0, 0, 0, 0);
			this.labelHeaderStyle.fontStyle = FontStyle.Bold;
			this.labelHeaderStyle.fontSize = this.defaultControlFontSize;
			this.labelHeaderStyle.normal = new GUIStyleState
			{
				textColor = new Color(0.9f, 0.3f, 0.23f)
			};

			this.scrollBackground = new Texture2D(1, 1);
			this.scrollBackground.SetPixel(0, 0, new Color(0f, 0f, 0f, 0.8f));
			this.scrollBackground.Apply();
			
			this.scrollViewStyle = new GUIStyle("scrollView");
			this.scrollViewStyle.normal.background = this.scrollBackground;
			this.scrollViewStyle.margin = new RectOffset(0, 0, 0, 0);
			this.scrollViewStyle.padding = new RectOffset(0, 0, 0, 0);
		}
	}

	public void DisplayCheatMenu()
	{
		DrawWithSelectedBackColor(false);
		if (GUI.Button(new Rect(0f, this.menuYOffset, this.defaultControlWidth, this.defaultControlHeight), this.displayCheats ? "Hide Cheats" : "Show Cheats", this.defaultButtonStyle))
		{
			this.displayCheats = !this.displayCheats;
		}
		if (this.displayCheats)
		{
			bool displayState = this.tabState == 1;
			bool displayCommands = this.tabState == 2;
			bool displayAdvanced = this.tabState == 3;
			DrawWithSelectedBackColor(displayState);
			if (GUI.Button(new Rect(0f, this.menuYOffset + this.defaultControlHeight, this.defaultControlWidth, this.defaultControlHeight), "State", this.defaultButtonStyle))
			{
				displayState = SetSelectedTab(1);
			}
			DrawWithSelectedBackColor(displayCommands);
			if (GUI.Button(new Rect(0f, this.menuYOffset + (this.defaultControlHeight * 2), this.defaultControlWidth, this.defaultControlHeight), "Commands", this.defaultButtonStyle))
			{
				displayCommands = SetSelectedTab(2);
			}
			DrawWithSelectedBackColor(displayAdvanced);
			if (GUI.Button(new Rect(0f, this.menuYOffset + (this.defaultControlHeight * 3), this.defaultControlWidth, this.defaultControlHeight), "Advanced", this.defaultButtonStyle))
			{
				displayAdvanced = SetSelectedTab(3);
			}
			DrawWithSelectedBackColor(false);

			if (displayState)
			{
				DrawStateTab();
			}
			else if (displayCommands)
			{
				DrawCommandsTab();
			}
			else if (displayAdvanced)
			{
				DrawAdvancedTab();
			}

			if(this.loadScenePrompt)
			{
				GUI.Window(-66, this.dumpConfirmWindowRect, new GUI.WindowFunction(this.LoadSceneFunc), "Load Scene");
			}
		}
	}

	public void DrawStateTab()
	{
		float scrollHeight = (float)Screen.height - (this.menuYOffset + this.defaultControlHeight) * 2f;
		int scrollItemCount = this.flowcharts.Length;
		for (int i = 0; i < this.flowcharts.Length; i++)
		{
			scrollItemCount += this.flowcharts[i].Variables.Count;
		}
		float scrollInternalHeight = (float)scrollItemCount * this.defaultControlHeight;
		scrollHeight = Math.Min(scrollInternalHeight, scrollHeight);
		
		Rect scrollRect = new Rect(this.defaultControlWidth, this.menuYOffset + this.defaultControlHeight, this.defaultControlWidth * 2f, scrollHeight);
		Rect scrollInternalRect = new Rect(0f, 0f, (this.defaultControlWidth * 2f) - this.scrollbarWidth, scrollInternalHeight);
		this.scrollStateViewVector = GUI.BeginScrollView(scrollRect, this.scrollStateViewVector, scrollInternalRect, false, true, GUI.skin.horizontalScrollbar, GUI.skin.verticalScrollbar, this.scrollViewStyle);
		for (int j = 0; j < this.flowcharts.Length; j++)
		{
			this.DrawStateChart(this.flowcharts[j]);
		}
		GUI.EndScrollView();
		
		//Hacky workaround for the ScrollView not taking mouse scrollwheel focus
		if (scrollRect.Contains(Input.mousePosition))
		{
			Input.ResetInputAxes();
		}
	}

	public void DrawCommandsTab()
	{
		float scrollHeight = (float)Screen.height - (this.menuYOffset + this.defaultControlHeight) * 2f;
		float scrollInternalHeight = (float)this.commandsList.Count * this.defaultControlHeight;
		scrollHeight = Math.Min(scrollInternalHeight, scrollHeight);
		
		Rect scrollRect = new Rect(this.defaultControlWidth, this.menuYOffset + this.defaultControlHeight, this.defaultControlWidth, scrollHeight);
		Rect scrollInternalRect = new Rect(0f, 0f, this.defaultControlWidth - this.scrollbarWidth, scrollInternalHeight);
		this.scrollCommandsViewVector = GUI.BeginScrollView(scrollRect, this.scrollCommandsViewVector, scrollInternalRect, false, true, GUI.skin.horizontalScrollbar, GUI.skin.verticalScrollbar, this.scrollViewStyle);
		for (int i = 0; i < this.commandsList.Count; i++)
		{
			GUILayoutOption[] layoutOption = this.commandsList[i].Length == 2 ? this.buttonHalfLayoutOptions : this.buttonLayoutOptions;
			GUILayout.BeginHorizontal();
			for (int j = 0; j < this.commandsList[i].Length; j++)
			{
				if(GUILayout.Button(this.commandsList[i][j].Key, this.defaultButtonStyle, layoutOption))
				{
					this.commandsList[i][j].Value();
				}
			}
			GUILayout.EndHorizontal();
		}
		GUI.EndScrollView();
	}

	public void DrawAdvancedTab()
	{
		float scrollHeight = (float)Screen.height - (this.menuYOffset + this.defaultControlHeight) * 2f;
		float scrollInternalHeight = (float)this.advancedList.Count * this.defaultControlHeight;
		scrollHeight = Math.Min(scrollInternalHeight, scrollHeight);

		Rect scrollRect = new Rect(this.defaultControlWidth, this.menuYOffset + this.defaultControlHeight, this.defaultControlWidth, scrollHeight);
		Rect scrollInternalRect = new Rect(0f, 0f, this.defaultControlWidth - this.scrollbarWidth, scrollInternalHeight);
		this.scrollAdvancedViewVector = GUI.BeginScrollView(scrollRect, this.scrollAdvancedViewVector, scrollInternalRect, false, true, GUI.skin.horizontalScrollbar, GUI.skin.verticalScrollbar, this.scrollViewStyle);

		for (int i = 0; i < this.advancedList.Count; i++)
		{
			GUILayoutOption[] layoutOption = this.commandsList[i].Length == 2 ? this.buttonHalfLayoutOptions : this.buttonLayoutOptions;
			GUILayout.BeginHorizontal();
			for (int j = 0; j < this.advancedList[i].Length; j++)
			{
				if(GUILayout.Button(this.advancedList[i][j].Key, this.defaultButtonStyle, layoutOption))
				{
					this.advancedList[i][j].Value();
				}
			}
			GUILayout.EndHorizontal();
		}
		GUI.EndScrollView();
	}
	
	public void DrawDebugMenu()
	{
		DrawWithSelectedBackColor(false);
		if (this.displayCheats && GUI.Button(new Rect(this.defaultControlWidth, this.menuYOffset, this.defaultControlWidth, this.defaultControlHeight), this.displayDebug ? "Hide Debug" : "Show Debug", this.defaultButtonStyle))
		{
			this.displayDebug = !this.displayDebug;
		}
		if (this.displayDebug)
		{
			if(this.autoSceneDumpPromt)
			{
				GUI.Window(-67, this.dumpConfirmWindowRect, new GUI.WindowFunction(this.DumpAllWindowFunc), "Dump All");
			}
			else
			{
				this.debugWindowRect = GUI.Window(-69, this.debugWindowRect, new GUI.WindowFunction(this.DebugWindowFunc), "Debug");
			}
		}
	}

	public void DrawWithSelectedBackColor(bool selected)
	{
		if(selected)
		{
			GUI.backgroundColor = this.buttonSelectedBackColor;
		}
		else
		{
			GUI.backgroundColor = this.buttonNormalBackColor;
		}
	}

	public void DrawStateChart(Flowchart chart)
	{
		GUILayout.Label(string.Format("FC:{0}", chart.name), this.labelHeaderStyle, new GUILayoutOption[0]);
		for (int i = 0; i < chart.Variables.Count; i++)
		{
			Variable variable = chart.Variables[i];
			this.DrawStateEntry(chart, variable);
		}
	}

	public void DrawStateEntry(Flowchart chart, Variable variable)
	{
		Type type = variable.GetType();
		if (type == typeof(BooleanVariable))
		{
			BooleanVariable booleanVariable = (BooleanVariable)variable;
			GUILayout.BeginHorizontal(new GUILayoutOption[0]);
			GUILayout.Label("(Bool)", this.labelStyle, new GUILayoutOption[0]);
			if (GUILayout.Button(booleanVariable.Value.ToString(), this.boolButtonStyle, new GUILayoutOption[0]))
			{
				chart.SetBooleanVariable(variable.Key, !booleanVariable.Value);
			}
			GUILayout.Label(variable.Key, this.labelStyle, new GUILayoutOption[0]);
			GUILayout.FlexibleSpace();
			GUILayout.EndHorizontal();
			return;
		}
		if (type == typeof(IntegerVariable))
		{
			IntegerVariable integerVariable = (IntegerVariable)variable;
			GUILayout.BeginHorizontal(new GUILayoutOption[0]);
			GUILayout.Label("(Int)", this.labelStyle, new GUILayoutOption[0]);
			bool hitPlus = GUILayout.Button("+", this.intButtonStyle, new GUILayoutOption[0]);
			bool hitMinus = GUILayout.Button("-", this.intButtonStyle, new GUILayoutOption[0]);
			if(hitPlus || hitMinus)
			{
				int addValue = hitPlus ? GetIntFromModifierKeys() : -GetIntFromModifierKeys();
				integerVariable.Value += addValue;
				PlayerPrefs.SetInt(SetSaveProfile.SaveProfile + "_" + chart.SubstituteVariables(variable.Key), integerVariable.Value);
			}
			GUILayout.Label(string.Format("{0} - {1}", variable.Key, variable), this.labelStyle, new GUILayoutOption[0]);
			GUILayout.FlexibleSpace();
			GUILayout.EndHorizontal();
			return;
		}
		if (type == typeof(StringVariable))
		{
			GUILayout.BeginHorizontal(new GUILayoutOption[0]);
			GUILayout.Label(string.Format("({0}){1} - {2}", "String", variable.Key, variable), this.labelStyle, new GUILayoutOption[0]);
			GUILayout.FlexibleSpace();
			GUILayout.EndHorizontal();
			return;
		}
		if (type == typeof(FloatVariable))
		{
			FloatVariable floatVariable = (FloatVariable)variable;
			GUILayout.BeginHorizontal(new GUILayoutOption[0]);
			GUILayout.Label("(Float)", this.labelStyle, new GUILayoutOption[0]);
			bool hitPlus = GUILayout.Button("+", this.intButtonStyle, new GUILayoutOption[0]);
			bool hitMinus = GUILayout.Button("-", this.intButtonStyle, new GUILayoutOption[0]);
			if(hitPlus || hitMinus)
			{
				float addValue = hitPlus ? GetFloatFromModifierKeys() : -GetFloatFromModifierKeys();
				floatVariable.Value += addValue;
				PlayerPrefs.SetFloat(SetSaveProfile.SaveProfile + "_" + chart.SubstituteVariables(variable.Key), floatVariable.Value);
			}
			GUILayout.Label(string.Format("{0} - {1:0.00}", variable.Key, floatVariable.Value), this.labelStyle, new GUILayoutOption[0]);
			GUILayout.FlexibleSpace();
			GUILayout.EndHorizontal();
			return;
		}
		GUILayout.BeginHorizontal(new GUILayoutOption[0]);
		GUILayout.Label(string.Format("({0}){1} - {2}", type.Name.Replace("Variable", ""), variable.Key, variable), this.labelStyle, new GUILayoutOption[0]);
		GUILayout.FlexibleSpace();
		GUILayout.EndHorizontal();
	}
	
	public int GetIntFromModifierKeys()
	{
		bool shiftDown = Input.GetKey(KeyCode.LeftShift) || Input.GetKey(KeyCode.RightShift);
		bool ctrlDown = Input.GetKey(KeyCode.LeftControl) || Input.GetKey(KeyCode.RightControl);
		int result = shiftDown ? (ctrlDown ? 100 : 10) : 1;
		return result;
	}
	
	public float GetFloatFromModifierKeys()
	{
		bool shiftDown = Input.GetKey(KeyCode.LeftShift) || Input.GetKey(KeyCode.RightShift);
		bool ctrlDown = Input.GetKey(KeyCode.LeftControl) || Input.GetKey(KeyCode.RightControl);
		float result = shiftDown ? (ctrlDown ? 1f : 0.1f) : 0.05f;
		return result;
	}

	public bool SetSelectedTab(int index)
	{
		bool result = false;
		if(this.tabState == index)
		{
			this.tabState = 0;
		}
		else
		{
			this.tabState = index;
			result = true;
		}

		return result;
	}

	public void AddInt(string name, int value)
	{
		bool breakOut = false;
		for (int j = 0; j < this.flowcharts.Length; j++)
		{
			if(breakOut) break;
					
			for (int i = 0; i < this.flowcharts[j].Variables.Count; i++)
			{
				if(breakOut) break;
						
				if(this.flowcharts[j].Variables[i].Key == name)
				{
					IntegerVariable variable = (IntegerVariable)this.flowcharts[j].Variables[i];
					variable.Value += value;
					PlayerPrefs.SetInt(SetSaveProfile.SaveProfile + "_" + this.flowcharts[j].SubstituteVariables(variable.Key), variable.Value);
					breakOut = true;
				}
			}
		}
	}

	public void SetInt(string name, int value)
	{
		bool breakOut = false;
		for (int j = 0; j < this.flowcharts.Length; j++)
		{
			if(breakOut) break;
					
			for (int i = 0; i < this.flowcharts[j].Variables.Count; i++)
			{
				if(breakOut) break;
						
				if(this.flowcharts[j].Variables[i].Key == name)
				{
					IntegerVariable variable = (IntegerVariable)this.flowcharts[j].Variables[i];
					variable.Value = value;
					PlayerPrefs.SetInt(SetSaveProfile.SaveProfile + "_" + this.flowcharts[j].SubstituteVariables(variable.Key), variable.Value);
					breakOut = true;
				}
			}
		}
	}

	public int GetInt(string name)
	{
		int result = 0;
		bool breakOut = false;
		for (int j = 0; j < this.flowcharts.Length; j++)
		{
			if(breakOut) break;
					
			for (int i = 0; i < this.flowcharts[j].Variables.Count; i++)
			{
				if(breakOut) break;
						
				if(this.flowcharts[j].Variables[i].Key == name)
				{
					IntegerVariable variable = (IntegerVariable)this.flowcharts[j].Variables[i];
					result = variable.Value;
					breakOut = true;
				}
			}
		}
		return result;
	}

	public void DebugWindowFunc(int id)
	{
		GUILayout.Label("Dump Scene:", this.labelHeaderStyle, new GUILayoutOption[0]);
		if (GUILayout.Button("Dump Current", defaultButtonStyle, new GUILayoutOption[0]))
		{
			this.DumpScene();
		}
		if (GUILayout.Button("Dump All", defaultButtonStyle, new GUILayoutOption[0]))
		{
			this.loadScenePrompt = false;
			this.autoSceneDumpPromt = true;
		}
		GUILayout.Label("Scene", this.labelHeaderStyle, new GUILayoutOption[0]);
		GUILayout.Label(this.lastScene, this.labelStyle, new GUILayoutOption[0]);
		GUILayout.BeginHorizontal(new GUILayoutOption[0]);
		GUILayout.Label("Charts", this.labelHeaderStyle, new GUILayoutOption[0]);
		GUILayout.FlexibleSpace();
		GUILayout.Label(this.foundCharts.ToString(), this.labelStyle, new GUILayoutOption[0]);
		GUILayout.EndHorizontal();
		GUILayout.BeginHorizontal(new GUILayoutOption[0]);
		GUILayout.Label("Init", this.labelHeaderStyle, new GUILayoutOption[0]);
		GUILayout.FlexibleSpace();
		GUILayout.Label(this.initCounter.ToString(), this.labelStyle, new GUILayoutOption[0]);
		GUILayout.EndHorizontal();
		GUI.DragWindow(new Rect(0f, 0f, 10000f, 10000f));
	}
	
	public void DumpAllWindowFunc(int id)
	{
		GUILayout.Label("This will load and dump every scene in the game", this.labelStyle, new GUILayoutOption[0]);
		GUILayout.Label("This might take awhile, especially on slower machines", this.labelStyle, new GUILayoutOption[0]);
		GUILayout.Label("The screen will appear black during this process", this.labelStyle, new GUILayoutOption[0]);
		GUILayout.Label("Make sure to keep the game in focus or the progress will be paused!", this.labelStyle, new GUILayoutOption[0]);
		GUILayout.Label("", this.labelHeaderStyle, new GUILayoutOption[0]);
		GUILayout.Label("Are you sure?", this.labelHeaderStyle, new GUILayoutOption[0]);
		GUILayout.BeginHorizontal(new GUILayoutOption[0]);
		bool yesPressed = GUILayout.Button("Yes", defaultButtonStyle, new GUILayoutOption[0]);
		bool noPressed = GUILayout.Button("No", defaultButtonStyle, new GUILayoutOption[0]);
		if(yesPressed || noPressed)
		{
			this.autoSceneDump = yesPressed;
			this.displayDebug = !yesPressed;
			this.displayCheats = !yesPressed;
			this.autoSceneDumpPromt = false;
		}
		GUILayout.EndHorizontal();
	}

	public void LoadSceneFunc(int id)
	{
		GUILayout.Label("Beware, Here be Dragons -EXPERIMENTAL-", this.labelHeaderStyle, new GUILayoutOption[0]);
		GUILayout.Label("Could break saves and cause softlocks use at own risk!", this.labelHeaderStyle, new GUILayoutOption[0]);
		GUILayout.Label("You can find a list of scenenames by dumping all scenes", this.labelStyle, new GUILayoutOption[0]);
		GUILayout.Label("with the debug menu", this.labelStyle, new GUILayoutOption[0]);
		GUILayout.BeginHorizontal(new GUILayoutOption[0]);
		GUILayout.Label("Scene Name", this.labelStyle, new GUILayoutOption[0]);
		GUILayout.FlexibleSpace();
		this.sceneNameInput = GUILayout.TextField(this.sceneNameInput, GUILayout.Width(this.dumpConfirmWindowRect.width - this.defaultControlWidth));
		GUILayout.EndHorizontal();
		GUILayout.Label("Are you sure?", this.labelHeaderStyle, new GUILayoutOption[0]);
		GUILayout.BeginHorizontal(new GUILayoutOption[0]);
		bool yesPressed = GUILayout.Button("Yes", defaultButtonStyle, new GUILayoutOption[0]);
		bool noPressed = GUILayout.Button("No", defaultButtonStyle, new GUILayoutOption[0]);
		if(yesPressed || noPressed)
		{
			this.displayCheats = !yesPressed;
			this.loadScenePrompt = false;
			if(yesPressed)
			{
				SceneManager.LoadScene(this.sceneNameInput);
			}
		}
		GUILayout.EndHorizontal();
	}

	public void DumpScene()
	{
		Scene activeScene = SceneManager.GetActiveScene();
		GameObject[] rootGameObjects = activeScene.GetRootGameObjects();
		using (FileStream fileStream = File.Create(Path.Combine(Application.dataPath, activeScene.name + ".dmp")))
		{
			using (StreamWriter streamWriter = new StreamWriter(fileStream))
			{
				try
				{
					foreach (GameObject gameObject in rootGameObjects)
					{
						streamWriter.WriteLine("{0}", gameObject.name);
						Dictionary<Block, List<Command>> dictionary = new Dictionary<Block, List<Command>>();
						foreach (Block key in gameObject.GetComponents<Block>())
						{
							dictionary.Add(key, new List<Command>());
						}
						foreach (Command command in gameObject.GetComponents<Command>())
						{
							dictionary[command.ParentBlock].Add(command);
						}
						foreach (KeyValuePair<Block, List<Command>> keyValuePair in dictionary)
						{
							keyValuePair.Value.Sort((Command s1, Command s2) => s1.CommandIndex.CompareTo(s2.CommandIndex));
							streamWriter.WriteLine("\t(Block){0}", keyValuePair.Key.BlockName);
							foreach (Command command2 in keyValuePair.Value)
							{
								Type type = command2.GetType();
								string text = this.FormatIndent(2, command2);
								if (type == typeof(SaveVariable))
								{
									text += string.Format("(SaveVariable) {0}", ((SaveVariable)command2).key);
								}
								else if (type == typeof(LoadVariable))
								{
									LoadVariable loadVariable = (LoadVariable)command2;
									text += string.Format("(LoadVariable) {0}", loadVariable.key);
								}
								else if (type == typeof(Call))
								{
									Call call = (Call)command2;
									text += string.Format("(Call) {0} - {1}", (call.targetBlock != null) ? call.targetBlock.blockName : "null", (call.targetFlowchart != null) ? call.targetFlowchart.name : "null");
								}
								else if (type == typeof(SetVariable))
								{
									string arg = this.FormatSetVariable((SetVariable)command2);
									text += string.Format("(SetVariable) {0}", arg);
								}
								else if (type == typeof(Say))
								{
									Say say = (Say)command2;
									text += string.Format("(Say) {0} - {1}", (say.character != null) ? say.character.NameText : "null", (say.storyText != null) ? say.storyText.Replace("\r", "").Replace("\n", "") : "null");
								}
								else if (type == typeof(LoadScene))
								{
									string value = ((LoadScene)command2)._sceneName.Value;
									text += string.Format("(LoadScene) {0}", value);
								}
								else if (type == typeof(If))
								{
									If condition = (If)command2;
									string arg2 = this.FormatVariable(condition);
									text += string.Format("(If) {0}", arg2);
								}
								else if (type == typeof(ElseIf))
								{
									string arg3 = this.FormatVariable((ElseIf)command2);
									text += string.Format("(ElseIf) {0}", arg3);
								}
								else if (type == typeof(Menu))
								{
									Menu menu = (Menu)command2;
									string arg4 = string.Format("{0} - {1}", menu.text, (menu.targetBlock != null) ? menu.targetBlock.BlockName : "null");
									text += string.Format("(Menu) {0}", arg4);
								}
								else if (type == typeof(SetActive))
								{
									SetActive setActive = (SetActive)command2;
									string arg5 = "null";
									if (setActive._targetGameObject.Value != null)
									{
										arg5 = setActive._targetGameObject.Value.name;
									}
									text += string.Format("(SetActive) {0} {1}", arg5, setActive.activeState.Value);
								}
								else if (type == typeof(SetText))
								{
									SetText setText = (SetText)command2;
									string arg6 = "null";
									if (setText.text.Value != null)
									{
										arg6 = setText.text.Value.Replace("\r", "").Replace("\n", "");
									}
									text += string.Format("(SetText) {0}", arg6);
								}
								else if (type == typeof(RandomInteger))
								{
									RandomInteger ranInteger = (RandomInteger)command2;
									string arg7 = "null";
									if (ranInteger.variable != null)
									{
										arg7 = ranInteger.variable.Key;
									}
									text += string.Format("(RandomInteger) Min:{0} Max:{1} - {2}", ranInteger.minValue.Value, ranInteger.maxValue.Value, arg7);
								}
								else if(type == typeof(InvokeEvent))
								{
									InvokeEvent invokeEvent = (InvokeEvent)command2;
									UnityEngine.Events.UnityEventBase unityEvent = null;

									switch (invokeEvent.invokeType)
									{
									case InvokeType.Static:
										unityEvent = invokeEvent.staticEvent;
										break;
									case InvokeType.DynamicBoolean:
										unityEvent = invokeEvent.booleanEvent;
										break;
									case InvokeType.DynamicInteger:
										unityEvent = invokeEvent.integerEvent;
										break;
									case InvokeType.DynamicFloat:
										unityEvent = invokeEvent.floatEvent;
										break;
									case InvokeType.DynamicString:
										unityEvent = invokeEvent.stringEvent;
										break;
									}
									int eventCount = unityEvent.GetPersistentEventCount();
									string arg8 = eventCount == 0 ? "null" : "";
									for (int i = 0; i < eventCount; i++)
									{
										arg8 += string.Format(" {0}",unityEvent.GetPersistentMethodName(i));
									}
									text += string.Format("(InvokeEvent) Type: {0} -{1}", invokeEvent.invokeType, arg8);
								}
								else if (type == typeof(Else) || type == typeof(End) || type == typeof(FadeScreen) || type == typeof(Wait) || type == typeof(SetMenuDialog))
								{
									text += string.Format("({0})", type.Name);
								}
								else
								{
									string arg6 = command2.ToString().Replace("(" + type.FullName + ")", "");
									text += string.Format("({0}) - {1}", type.Name, arg6);
								}
								streamWriter.WriteLine(text);
							}
						}
					}
				}
				catch(Exception ex)
				{
					string failedDump = string.Format("ERROR; REPORT THIS, Exception: {0}", ex);
					streamWriter.WriteLine(failedDump);
				}
			}
		}
	}

	public string FormatIndent(int baseCount, Command command)
	{
		int num = command.IndentLevel + baseCount;
		string text = "";
		for (int i = 0; i < num; i++)
		{
			text += "\t";
		}
		return text;
	}

	public string FormatVariable(VariableCondition condition)
	{
		Variable variable = condition.variable;
		string result = "-variable null-";
		if (variable != null)
		{
			Type type = variable.GetType();
			if (type == typeof(IntegerVariable))
			{
				result = string.Format("(int){0} {1} {2}", variable.key, this.FormatCompareOperator(condition.compareOperator), condition.integerData.Value);
			}
			else if (type == typeof(BooleanVariable))
			{
				result = string.Format("(bool){0} {1} {2}", variable.key, this.FormatCompareOperator(condition.compareOperator), condition.booleanData.Value);
			}
			else if (type == typeof(StringVariable))
			{
				result = string.Format("(string){0} {1} {2}", variable.key, this.FormatCompareOperator(condition.compareOperator), condition.stringData.Value);
			}
			else if (type == typeof(FloatVariable))
			{
				result = string.Format("(float){0} {1} {2}", variable.key, this.FormatCompareOperator(condition.compareOperator), condition.floatData.Value);
			}
			else
			{
				result = string.Format("{0} {1} Unknown", variable.key, this.FormatCompareOperator(condition.compareOperator));
			}
		}
		return result;
	}

	public string FormatSetVariable(SetVariable setVariable)
	{
		Variable variable = setVariable.variable;
		string result = "null";
		if (variable != null)
		{
			Type type = variable.GetType();
			if (type == typeof(IntegerVariable))
			{
				result = string.Format("(int){0} {1} {2}", variable.key, this.FormatSetOperator(setVariable.setOperator), setVariable.integerData.Value);
			}
			else if (type == typeof(BooleanVariable))
			{
				result = string.Format("(bool){0} {1} {2}", variable.key, this.FormatSetOperator(setVariable.setOperator), setVariable.booleanData.Value);
			}
			else if (type == typeof(StringVariable))
			{
				result = string.Format("(string){0} {1} {2}", variable.key, this.FormatSetOperator(setVariable.setOperator), setVariable.stringData.Value);
			}
			else if (type == typeof(FloatVariable))
			{
				result = string.Format("(float){0} {1} {2}", variable.key, this.FormatSetOperator(setVariable.setOperator), setVariable.floatData.Value);
			}
			else
			{
				result = string.Format("{0} {1} Unknown", variable.key, this.FormatSetOperator(setVariable.setOperator));
			}
		}
		return result;
	}

	public string FormatSetOperator(SetOperator setOperator)
	{
		string result = null;
		if (setOperator == SetOperator.Add)
		{
			result = "+";
		}
		else if (setOperator == SetOperator.Assign)
		{
			result = "=";
		}
		else if (setOperator == SetOperator.Divide)
		{
			result = "/";
		}
		else if (setOperator == SetOperator.Multiply)
		{
			result = "*";
		}
		else if (setOperator == SetOperator.Negate)
		{
			result = "=!";
		}
		else if (setOperator == SetOperator.Subtract)
		{
			result = "-";
		}
		return result;
	}

	public string FormatCompareOperator(CompareOperator compareOperator)
	{
		string result = null;
		if (compareOperator == CompareOperator.Equals)
		{
			result = "==";
		}
		else if (compareOperator == CompareOperator.GreaterThan)
		{
			result = ">";
		}
		else if (compareOperator == CompareOperator.GreaterThanOrEquals)
		{
			result = ">=";
		}
		else if (compareOperator == CompareOperator.LessThan)
		{
			result = "<";
		}
		else if (compareOperator == CompareOperator.LessThanOrEquals)
		{
			result = "<=";
		}
		else if (compareOperator == CompareOperator.NotEquals)
		{
			result = "!=";
		}
		return result;
	}
	
	public bool DoAutoSceneDump(out string nextSceneOut, Scene activeScene)
	{
		bool result;
		if (!this.sceneDumpDict.ContainsKey(activeScene.name) || !this.sceneDumpDict[activeScene.name])
		{
			this.sceneDumpDict[activeScene.name] = true;
			this.DumpScene();
		}
		GameObject[] rootGameObjects = activeScene.GetRootGameObjects();
		for (int i = 0; i < rootGameObjects.Length; i++)
		{
			foreach (LoadScene loadScene in rootGameObjects[i].GetComponents<LoadScene>())
			{
				if (!this.sceneDumpDict.ContainsKey(loadScene._sceneName.Value))
				{
					this.sceneDumpDict.Add(loadScene._sceneName.Value, false);
				}
			}
		}
		string nextScene = null;
		foreach (KeyValuePair<string, bool> keyValuePair in this.sceneDumpDict)
		{
			if (!keyValuePair.value)
			{
				nextScene = keyValuePair.key;
				break;
			}
		}
		if (nextScene != null)
		{
			result = true;
			nextSceneOut = nextScene;
		}
		else
		{
			result = false;
			nextSceneOut = null;
		}	
		return result;
	}

	public static CheatMenu Instance;
	
	public string DetectedVersion;
	
	public string ExpectedVersion;
	
	public bool versionCheck;
	
	public bool versionMatched;

	public bool initFlowChart;

	public bool initGuiStyle;

	public bool displayCheats;

	public int tabState;

	public float scrollbarWidth;

	public string lastScene;

	public int foundCharts;

	public int initCounter;

	public bool displayDebug;

	public Vector2 scrollStateViewVector;

	public Vector2 scrollCommandsViewVector;

	public Vector2 scrollAdvancedViewVector;

	public GUIStyle labelStyle;

	public GUIStyle intButtonStyle;
	
	public GUIStyle boolButtonStyle;

	public GUIStyle scrollViewStyle;
	
	public GUIStyle defaultButtonStyle;

	public GUIStyle labelHeaderStyle;

	public GUILayoutOption[] buttonLayoutOptions;

	public GUILayoutOption[] buttonHalfLayoutOptions;

	public Color buttonNormalBackColor;

    public Color buttonSelectedBackColor;
	
	public float minButtonHeight;
	
	public int proposedItemCount;

	public int defaultControlHeight;
	
	public int defaultControlWidth;

	public int defaultControlFontSize;
	
	public Texture2D scrollBackground;

	public float menuYOffset;

	public bool debugMenu;
	
	public bool autoSceneDump;

	public bool autoSceneDumpPromt;

	public bool loadScenePrompt;
	
	public Rect debugWindowRect;
	
	public Flowchart[] flowcharts;

	public HashSet<string> blackListScenes;
	
	public Rect dumpConfirmWindowRect;
	
	public string sceneNameInput;
	
	public Dictionary<string, bool> sceneDumpDict;
	
	public List<KeyValuePair<string, Action>[]> commandsList;

	public List<KeyValuePair<string, Action>[]> advancedList;
}
